package cn.codeforfun.interceptor.adapter;

import cn.codeforfun.consts.WeixinConst;
import cn.codeforfun.interceptor.CallbackInterceptor;
import cn.codeforfun.utils.HttpKit;
import com.qq.weixin.aes.AesException;
import com.qq.weixin.aes.WXBizMsgCrypt;
import me.chanjar.weixin.common.util.crypto.SHA1;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * 接收微信消息拦截器
 */
public class CallbackInterceptorAdaptor implements HandlerInterceptor {
    @Autowired
    private WeixinConst weixinConst;
    private Logger log = Logger.getLogger(CallbackInterceptorAdaptor.class);

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {//java.lang.ClassCastException: org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();

            //获取方法级拦截器注解
            CallbackInterceptor annotation = method.getAnnotation(CallbackInterceptor.class);
            if (annotation != null) {
                log.info("CallbackInterceptorAdaptor is intecept.The method name is " + method.getName());
                if (isConfigServerRequest(request)) {
                    // 如果是服务器配置请求，则配置服务器并返回(get请求)
                    if (checkSignature(request)) {
                        //验证签名正确
                        configServer(request, response);
                    } else {
                        //验证签名失败
                        response.getWriter().write("你谁啊!!!");
                    }
                    return false;
                } else {
                    // 如果不是服务器配置请求(post)
                    String param = HttpKit.readData(request);
                    request.setAttribute("inXml", param);
                    if (param.contains("Encrypt")) {
                        //密文需解密
                        param = decryptMsg(request);
                        request.setAttribute("inXml", param);
                    }
                    return true;
                }
            }
        }

        // 没有注解通过拦截
        return true;
    }


    /**
     * 是否为开发者中心保存服务器配置的请求(get方法)
     */
    private boolean isConfigServerRequest(HttpServletRequest request) {
        return StringUtils.isNotEmpty(request.getParameter("echostr"));
    }

    /**
     * 验证是不是微信发来的消息
     */
    private boolean checkSignature(HttpServletRequest request) {
        String signature = request.getParameter("signature");//公众号
        String nonce = request.getParameter("nonce");
        String timestamp = request.getParameter("timestamp");
        String echostr = request.getParameter("echostr");
        boolean flag;
        if (!SHA1.gen(weixinConst.getToken(), timestamp, nonce).equals(signature)) {
            // 消息签名不正确，说明不是公众平台发过来的消息
            log.error("非法请求");
            flag = false;
        } else {
            flag = true;
        }
        return flag;
    }

    /**
     * 配置开发者中心微信服务器所需的 url 与 token
     *
     * @return true 为config server 请求，false 正式消息交互请求
     */

    public void configServer(HttpServletRequest request, HttpServletResponse response) {
        // 通过 echostr 判断请求是否为配置微信服务器回调所需的 url 与 token
        try {
            String echostr = (String) request.getAttribute("returnEchostr");
            if (echostr != null) {
                response.getWriter().write(echostr);
            } else {
                response.getWriter().write(request.getParameter("echostr"));
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 将密文解密
     *
     * @return
     */
    private String decryptMsg(HttpServletRequest request) {
        try {
            WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(weixinConst.getToken(), weixinConst.getAeskey(), weixinConst.getAppid());
            return wxBizMsgCrypt.decryptMsg(request.getParameter("msg_signature"), request.getParameter("timestamp"), request.getParameter("nonce"), String.valueOf(request.getAttribute("inXml")));
        } catch (AesException e) {
            log.error(e.getMessage());
        }
        return null;
    }
}
